package com.example.utils;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import com.example.gcmpractice.R;
import com.google.android.gcm.GCMRegistrar;

import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;

/**
 * This class contains static functions and variables that are used to  communicate with the
 * application server.
 * <p>
 * The developer is free to add onto and modify the class so it can use the server's other functions
 * besides push notification.
 * @author Administrator
 *
 */

public final class ServerFunctions {

	/**
	 * This is your application server's base URL. Any service URL that the server provides needs to be
	 * in the format of BASE_URL + EXAMPLE_SERVICE_URL.
	 * <p>
	 * Make sure there is a forward slash at the end of the string.
	 * 
	 */
	public static final String BASE_URL = "http://10.0.1.62:8080/gcm-demo/";
	/**
	 * This is your application server's URL that handles device registration. By subscribing to the
	 * server, the device is now eligible to receive push notification from the server, which is powered
	 * by Google.
	 */
	public static final String REG_URL = "register";
	/**
	 * This is the URL that unsubscribes push notification.
	 */
	public static final String UNREG_URL = "unregister";
	
	/**
	 * This is the parameter fields the app will fill out when subscribing/unsubscribing with the
	 * server for push notification.
	 */
	public static final String PARAM_REGID = "regId";
	
	/**
	 * This function launches a HTTP POST request to the server. It does not expect a 
	 * response besides just a response code.
	 * <p>
	 * It is highly encouraged to create different postRequest functions to handle other forms of requests,
	 * since the function is tailored to handle device registrations only.
	 * 
	 * @param serviceURL The URL of the server's service.
	 * @param paramMap A mapping of keys and values. It is essentially the data to be sent to the server.
	 * @throws IOException If the POST request cannot be made
	 */
	public static void postRequest(String serviceURL, HashMap<String, String> paramMap) throws IOException {
		byte[] data = BasicFunctions.convertParamMapToBytes(paramMap);
		HttpURLConnection postConnection = null;
		try {
			//Create the URL, make a socket. The class HttpURLConnection does these for you.
			URL url = new URL(serviceURL);
			postConnection = (HttpURLConnection) url.openConnection();
			
			//Set some connection properties suitable for a post request
			postConnection.setDoOutput(true);
			postConnection.setUseCaches(false);
	        postConnection.setRequestMethod("POST");
	        //The content of this request is a POST responding to a form.
	        postConnection.setRequestProperty("Content-Type", 
	                "application/x-www-form-urlencoded;charset=UTF-8");
	        //We know the length of the content ahead of time.
	        postConnection.setFixedLengthStreamingMode(data.length);
	        
	        //Connect to the URL that'll serve the app's request.
	        postConnection.connect();
	        
	        //Write the post data to the server.
	        OutputStream out = new BufferedOutputStream(postConnection.getOutputStream());
	        out.write(data);
	        out.flush();
	        out.close();
	        
	        //The next few lines of code demonstrates how to receive responses from the application server
	        //such as response code, messages and so on.
	        
	        //One way of getting response data is to read from the header fields, which are set by the server.
	        //
	        //This method is rather limiting in the amount of data the response can contain, but is
	        //a quick and dirty way to get small response, as demonstrated below:
	        //
	        //String sHeaderValue = postConnection.getHeaderField("Your_Header_Key");
	        
	        //Another form of response data is just the response code.
	        int responseCode = postConnection.getResponseCode();
	        //If the response is a proper, non-error response, read the response body, if need to.
	        if (responseCode == HttpURLConnection.HTTP_ACCEPTED ||
	        		responseCode == HttpURLConnection.HTTP_OK) {
	        	
		        
		        //To read a response body, open an input stream and extract the string from it.
		        //It is up to the implementer to decode the body, such as in XML or JSON.
	        	
	        	//InputStream in = new BufferedInputStream(postConnection.getInputStream());
		        //String responseBody = BasicFunctions.inputStreamToString(in);
	        	
	        	//Parse the response body here.
	        }
	        else {
	        	//Handle your error here, such as throwing an exception.
	        	throw new IOException("Post Request failed. Error code: " + responseCode);
	        }
		} 
		catch (MalformedURLException e) {
			throw new MalformedURLException("Post request failed. Invalid URL: " + serviceURL);
		}
		finally {
			//If there has been some exception, make sure the connection is closed.
			if (postConnection != null) {
				postConnection.disconnect();
			}
		}
	}

	/**
	 * Posts a request to unsubscribe from the server.
	 * 
	 * This function should not be called except by GCMIntentService's callback methods.
	 * 
	 * @param appContext The application's context.
	 * @param rID The registration ID given by Google Cloud Messaging.
	 */
	public static void unregisterWithServer(Context appContext, String rID) {
		HashMap<String, String> params = new HashMap<String, String>();
	    params.put(PARAM_REGID, rID);
	    try {
			postRequest(BASE_URL + UNREG_URL, params);
		} catch (IOException e) {
			//The phone is still registered with the application server.
			//It's not necessary to try and unregister with the application server again.
			
			PendingIntent noActIntent = NotificationFunctions.makeNotifHandlerNoAction(appContext);
			Notification notif = NotificationFunctions.makeNotification(appContext, 
					noActIntent, 
					"Push Notification Error", 
					System.currentTimeMillis(), 
					Constants.APP_NAME, 
					e.getMessage(), 
					R.drawable.ic_notify);
			NotificationFunctions.broadcastNotification(Constants.HTTP_POST_ERROR, appContext, notif);
		}
	    //In either case, the app no longer subscribes with the application server.
	    GCMRegistrar.setRegisteredOnServer(appContext, false);
	}

	/**
	 * Posts a request to the server to subscribe for push notification.
	 * 
	 * This function should not be called except by GCMIntentService's callback methods.
	 * 
	 * @param appContext The application's context.
	 * @param rID The registration ID given by Google Cloud Messaging.
	 */
	public static void registerWithServer(Context appContext, String rID) {
	    HashMap<String, String> params = new HashMap<String, String>();
	    params.put(PARAM_REGID, rID);
	    try {
			postRequest(BASE_URL + REG_URL, params);
			GCMRegistrar.setRegisteredOnServer(appContext, true);
		} catch (IOException e) {
			//The phone could not register with the application server. No push notification will be delivered.
			//Notify that the user needs to try again.
			//BasicFunctions.buildNotification(0, appContext, "Registration failed", "RegWithGCM");
			
			PendingIntent noActIntent = NotificationFunctions.makeNotifHandlerNoAction(appContext);
			Notification notif = NotificationFunctions.makeNotification(appContext, 
					noActIntent, 
					"Push Notification Error", 
					System.currentTimeMillis(), 
					Constants.APP_NAME, 
					e.getMessage(), 
					R.drawable.ic_notify);
			NotificationFunctions.broadcastNotification(Constants.HTTP_POST_ERROR, appContext, notif);
			
		}
	}

}
